package com.jml.task.lock.impl;

import com.jml.task.utils.ZkClientUtils;
import org.I0Itec.zkclient.IZkDataListener;
import org.springframework.stereotype.Component;

import java.util.concurrent.CountDownLatch;

/**
 * 普通的zk锁
 */
@Component
public class ZookeeperTemplateLock extends ZookeeperAbstractTemplateLock {
    /**
     * 分布式锁 路径
     */
    private String lock = "/lockPath";
    private CountDownLatch countDownLatch = new CountDownLatch(1);

    @Override
    public boolean tryLock() {
        // 获取锁
        /**
         * 多个jvm同时在zk上创建一个临时节点/lockPath,
         * 最终只能够有一个jvm创建临时节点成功，如果能够创建
         * 临时节点成功jvm 表示获取锁成功能够正常执行业务逻辑，
         * 如果没有创建临时节点成功的jvm，则表示获取锁失败。
         * 获取锁失败之后，可以采用不断重试策略，重试多次
         * 获取锁失败之后，当前的jvm就进入到阻塞状态。
         */
        try {
            ZkClientUtils.newZkClient().createEphemeral(lock);
            return true;
        } catch (Exception e) {
            // 失败 其他jvm已经创建该节点成功
            return false;
        }

    }

    @Override
    protected void waitLock() {
        // 创建一个事件监听
        IZkDataListener iZkDataListener = new IZkDataListener() {

            @Override
            public void handleDataChange(String s, Object o) throws Exception {
            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                //当我们节点被删除之后，我们应该从新被唤醒
                countDownLatch.countDown();
            }
        };
        ZkClientUtils.getZkClient().subscribeDataChanges(lock, iZkDataListener);
        try {
            if (ZkClientUtils.getZkClient().exists(lock)) {
                //让当前线程阻塞
                countDownLatch.await();
            }

        } catch (Exception e) {

        }
        // 当我们节点被删除之后，我们应该从新被唤醒 移除事件监听
        ZkClientUtils.getZkClient().unsubscribeDataChanges(lock, iZkDataListener);
    }


}
